package com.gitee.qdbp.general.common.biz.sequence.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.general.common.api.sequence.model.SequenceBean;
import com.gitee.qdbp.general.common.api.sequence.model.StrongSequenceBean;
import com.gitee.qdbp.general.common.api.sequence.model.StrongSequenceRule;
import com.gitee.qdbp.general.common.api.sequence.model.StrongSequenceWhere;
import com.gitee.qdbp.general.common.api.sequence.service.IStrongSequenceGenerator;
import com.gitee.qdbp.general.common.biz.sequence.basic.StrongSequenceBasic;
import com.gitee.qdbp.general.common.biz.sequence.service.model.StrongSequenceResult;
import com.gitee.qdbp.general.common.error.GeneralErrorCode;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 复杂序列号业务处理类
 *
 * @author zhh
 * @version 160829
 */
// @Service
//SUPPORTS = 如果存在一个事务, 支持当前事务; 如果没有事务, 则非事务的执行
@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Throwable.class)
public class StrongSequenceGenerator implements IStrongSequenceGenerator, StrongSequenceQueryer {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(StrongSequenceGenerator.class);

    private StrongSequenceRule rule;
    /** 本机的主机编号(可为空) **/
    private String hostCode;
    /** 失败重试的等待时间 **/
    private long waitMillis = 200L;
    /** 失败尝试次数 **/
    private int retryTimes = 3;
    /** 默认的序号位数 **/
    private int digitNumber = 4;
    /** 初始值(0表示随机初始值, 大于0表示指定初始值) **/
    private long initValue = 0L;
    /** 默认的时间部分的格式 **/
    private String timeFormat = "yyMMdd";
    /** 使用存储过程 **/
    private boolean useDbFunction = false;

    @Autowired
    private StrongSequenceBasic strongSequenceBasic;
    @Autowired
    private StrongSequenceImpl strongSequenceImpl;

    /** 构造函数 **/
    public StrongSequenceGenerator() {
        StrongSequenceRule rule = new StrongSequenceRule();
        this.checkRule(rule);
        this.rule = rule;
    }

    /** 使用指定规则, 这个规则只会在首次且数据库没有配置规则时用到(即数据库规则优先) **/
    @Override
    public StrongSequenceGenerator use(StrongSequenceRule rule) {
        this.checkRule(rule);
        StrongSequenceGenerator generator = new StrongSequenceGenerator();
        generator.rule = rule;
        generator.strongSequenceBasic = this.strongSequenceBasic;
        generator.strongSequenceImpl = this.strongSequenceImpl;
        generator.hostCode = this.hostCode;
        generator.waitMillis = this.waitMillis;
        generator.retryTimes = this.retryTimes;
        generator.digitNumber = this.digitNumber;
        generator.initValue = this.initValue;
        generator.timeFormat = this.timeFormat;
        generator.useDbFunction = this.useDbFunction;
        return generator;
    }

    /**
     * 生成一个新的序号
     * 
     * @param type 类型
     * @param subtypes 子类型
     * @return 序号
     * @throws ServiceException
     */
    @Override
    public String generate(String type, String... subtypes) throws ServiceException {
        SequenceBean bean = execute(type, subtypes);
        return bean.getCurrValue();
    }

    /**
     * 生成一个新的序号
     * 
     * @param type 类型
     * @param subtypes 子类型
     * @return 序号
     * @throws ServiceException
     */
    @Override
    public SequenceBean execute(String type, String... subtypes) throws ServiceException {
        String msg = "Failed to generate StrongSequence. ";

        if (VerifyTools.isBlank(type)) {
            log.error(msg + "params is null: type");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 子类型合并为字符串
        String stype = SequenceTools.joinSubtypes(subtypes);

        // 如果失败, 重试几次
        for (int i = 0; i < retryTimes; i++) {

            StrongSequenceResult bean;
            try {
                // 使用存储过程或SQL生成一个新的序号
                if (useDbFunction) {
                    bean = strongSequenceImpl.callFunction(type, stype, rule);
                } else {
                    bean = strongSequenceImpl.execute(type, stype, rule, this);
                }
            } catch (ServiceException e) {
                if (ResultCode.DB_DUPLICATE_KEY.getCode().equals(e.getCode())) {
                    // 主键冲突, 说明其他线程已经新增这条记录了, 继续尝试
                    log.info("Failed to generate sequence({}), DUPLICATE KEY.", i + 1);
                    sleep(waitMillis);
                    continue;
                } else if (GeneralErrorCode.CONCURRENCY_CONFLICT.getCode().equals(e.getCode())) {
                    // 并发冲突, 说明其他线程已经修改掉这条记录了, 继续尝试
                    log.info("Failed to generate sequence({}), CONCURRENCY CONFLICT.", i + 1);
                    sleep(waitMillis);
                    continue;
                } else {
                    throw e;
                }
            }

            // 构建返回对象
            SequenceBean result = new SequenceBean();
            result.setCurrValue(SequenceTools.toString(bean, hostCode, bean.getCurrValue()));
            if (bean.getPrevValue() != null) {
                result.setPrevValue(SequenceTools.toString(bean, hostCode, bean.getPrevValue()));
            }
            return result;
        }

        log.error("Failed to generate sequence, type={}, subtype={}, try times={}!", type, stype, retryTimes);
        throw new ServiceException(GeneralErrorCode.GENERATE_SEQUENCE_ERROR);
    }

    /**
     * 查询序号的当前值
     * 
     * @param type 类型
     * @param subtypes 子类型
     * @return 当前序号
     * @throws ServiceException
     */
    @Override
    @Transactional(readOnly = true)
    public String query(String type, String... subtypes) throws ServiceException {
        String msg = "Failed to query StrongSequence. ";

        if (VerifyTools.isBlank(type)) {
            log.error(msg + "params is null: type");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 子类型合并为字符串
        String stype = SequenceTools.joinSubtypes(subtypes);

        StrongSequenceBean bean;
        { // 查询当前值
            StrongSequenceWhere where = new StrongSequenceWhere();
            where.setType(type);
            where.setSubtype(stype);
            bean = strongSequenceBasic.find(where);
        }

        if (bean == null || bean.getCurrValue() == null || bean.getCurrValue() <= 0) {
            return null;
        } else {
            return SequenceTools.toString(bean, hostCode, bean.getCurrValue());
        }
    }

    // 检查规则, 设置默认值
    private void checkRule(StrongSequenceRule rule) {
        if (rule.getInitValue() == null) {
            rule.setInitValue(initValue);
        }
        if (rule.getDigitNumber() == null || rule.getDigitNumber() <= 0) {
            rule.setDigitNumber(digitNumber);
        }
        if (VerifyTools.isBlank(rule.getTimeFormat())) {
            rule.setTimeFormat(timeFormat);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public StrongSequenceRule findRule(String type) throws ServiceException {

        // 查询subtype=*的通用配置数据
        StrongSequenceWhere where = new StrongSequenceWhere();
        where.setType(type);
        where.setSubtype("*");
        StrongSequenceBean bean = strongSequenceBasic.find(where);
        if (bean == null) return null;

        StrongSequenceRule rule = bean.to(StrongSequenceRule.class);
        checkRule(rule);
        return rule;
    }

    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException ignore) {
        }
    }

    /** 本机的主机编号(可为空) **/
    public String getHostCode() {
        return hostCode;
    }

    /** 本机的主机编号(可为空) **/
    public void setHostCode(String hostCode) {
        this.hostCode = hostCode;
    }

    /** 失败尝试次数 **/
    public int getRetryTimes() {
        return retryTimes;
    }

    /** 失败尝试次数 **/
    public void setRetryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
    }

    /** 默认的序号位数 **/
    public int getDigitNumber() {
        return digitNumber;
    }

    /** 默认的序号位数 **/
    public void setDigitNumber(int digitNumber) {
        this.digitNumber = digitNumber;
    }

    /** 获取初始值 **/
    public long getInitValue() {
        return initValue;
    }

    /** 设置初始值 **/
    public void setInitValue(long initValue) {
        this.initValue = initValue;
    }

    /** 默认的时间部分的格式 **/
    public String getTimeFormat() {
        return timeFormat;
    }

    /** 默认的时间部分的格式 **/
    public void setTimeFormat(String timeFormat) {
        this.timeFormat = timeFormat;
    }

    /** 使用存储过程 **/
    public boolean isUseDbFunction() {
        return useDbFunction;
    }

    /** 使用存储过程 **/
    public void setUseDbFunction(boolean useDbFunction) {
        this.useDbFunction = useDbFunction;
    }

}
